home *** CD-ROM | disk | FTP | other *** search
/ Freelog 22 / freelog 22.iso / Prog / Djgpp / GPC2952B.ZIP / lib / gcc-lib / djgpp / 2.952 / units / stringutils.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-02-08  |  19.7 KB  |  636 lines

  1. {
  2. Some routines for string handling on a higher level than those
  3. provided by the RTS.
  4.  
  5. Copyright (C) 1999-2001 Free Software Foundation, Inc.
  6.  
  7. Author: Frank Heckenbach <frank@pascal.gnu.de>
  8.  
  9. This file is part of GNU Pascal.
  10.  
  11. GNU Pascal is free software; you can redistribute it and/or modify
  12. it under the terms of the GNU General Public License as published by
  13. the Free Software Foundation; either version 2, or (at your option)
  14. any later version.
  15.  
  16. GNU Pascal is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. GNU General Public License for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with GNU Pascal; see the file COPYING. If not, write to the
  23. Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
  24. 02111-1307, USA.
  25.  
  26. As a special exception, if you link this file with files compiled
  27. with a GNU compiler to produce an executable, this does not cause
  28. the resulting executable to be covered by the GNU General Public
  29. License. This exception does not however invalidate any other
  30. reasons why the executable file might be covered by the GNU General
  31. Public License.
  32. }
  33.  
  34. {$gnu-pascal,B-,I-}
  35. {$if __GPC_RELEASE__ < 20000814}
  36. {$error This unit requires GPC release 20000814 or newer.}
  37. {$endif}
  38.  
  39. unit StringUtils;
  40.  
  41. interface
  42.  
  43. uses GPC;
  44.  
  45. { Appends Source to s, truncating the result if necessary. }
  46. procedure AppendStr (var s : String; const Source : String);
  47.  
  48. { Cuts s to MaxLength characters. If s is already MaxLength
  49.   characters or shorter, it doesn't change anything. }
  50. procedure StrCut (var s : String; MaxLength : Integer);
  51.  
  52. { Returns the number of disjoint occurences of SubStr in s. Returns
  53.   0 if SubStr is empty. }
  54. function  StrCount (const SubStr : String; s : String) : Integer;
  55.  
  56. { Returns s, with all disjoint occurences of Source replaced by
  57.   Dest. }
  58. function  StrReplace (const s, Source, Dest : String) : TString;
  59.  
  60. { Sets of characters accepted for `True' and `False' by
  61.   Char2Boolean and StrReadBoolean. }
  62. var
  63.   CharactersTrue  : CharSet = ['Y', 'y'];
  64.   CharactersFalse : CharSet = ['N', 'n'];
  65.  
  66. { If ch is an element of CharactersTrue, Dest is set to True,
  67.   otherwise if it is an element of CharactersFalse, Dest is set to
  68.   False. In both cases True is returned. If ch is not an element of
  69.   either set, Dest is set to False and False is returned. }
  70. function  Char2Boolean (ch : Char; var Dest : Boolean) : Boolean;
  71.  
  72. { Converts a digit character to its numeric value. Handles every
  73.   base up to 36 (0 .. 9, a .. z, upper and lower case recognized).
  74.   Returns -1 if the character is not a digit at all. If you want to
  75.   use it for a base < 36, you have to check if the result is smaller
  76.   than the base and not equal to -1. }
  77. function  Char2Digit (ch : Char) : Integer;
  78.  
  79. { Encode a string in a printable format (quoted printable and
  80.   surrounded with `"'). All occurences of `"' within the string are
  81.   encoded, so the result string contains exactly two `"' characters
  82.   (at the beginning and ending). This is useful to store arbitrary
  83.   strings in text files while keeping them as readable as possible
  84.   (which is the goal of the quoted printable encoding in general,
  85.   RFC 1521, section 5.1) and being able to read them back losslessly
  86.   (with UnQuoteString). }
  87. function  QuoteString (const s : String) : TString;
  88.  
  89. { Decode a string encoded by QuoteString (removing the `"' and
  90.   expanding quoted printable encoded characters). Returns True if
  91.   successful and False if the string has an invalid form. A string
  92.   returned by QuoteString is always valid. }
  93. function  UnQuoteString (var s : String) : Boolean;
  94.  
  95. { Decode a quoted-printable string (not enclosed in `"', unlike for
  96.   UnQuoteString). Returns True if successful and False if the string
  97.   has an invalid form. }
  98. function  UnQPString (var s : String) : Boolean;
  99.  
  100. { Replaces all tab characters in s with the appropriate amount of
  101.   spaces, assuming tab stops at every TabSize columns. Returns True
  102.   if successful and False if the expanded string would exceed the
  103.   capacity of s. In the latter case, some, but not all of the tabs
  104.   in s may have been expanded. }
  105. function  ExpandTabs (var s : String; TabSize : Integer) : Boolean;
  106.  
  107. { Returns s, with all occurences of C style escape sequences (e.g.
  108.   `\n') replaced by the characters they mean. If AllowOctal is True,
  109.   also octal character specifications (e.g. `\007') are replaced. If
  110.   RemoveQuoteChars is True, any other backslashes are removed (e.g.
  111.   `\*' -> `*' and `\\' -> `\'), otherwise they are kept, and also
  112.   `\\' is left as two backslashes then. }
  113. function  ExpandCEscapeSequences (const s : String; RemoveQuoteChars, AllowOctal : Boolean) : TString;
  114.  
  115. { String parsing routines }
  116.  
  117. {
  118.   All the following StrReadFoo functions behave similarly. They read
  119.   items from a string s, starting at index i, to a variable Dest.
  120.   They skip any space characters (spaces and tabs) by incrementing i
  121.   first. They return True if successful, False otherwise. i is
  122.   incremented accordingly if successful, otherwise i is left
  123.   unchanged, apart from the skipping of space characters, and Dest
  124.   is undefined. This behaviour makes it easy to use the functions in
  125.   a row like this:
  126.  
  127.     i := 1;
  128.     if StrReadInt    (s, i, Size)  and StrReadComma (s, i) and
  129.        StrReadQuoted (s, i, Name)  and StrReadComma (s, i) and
  130.        ...
  131.        StrReadReal   (s, i, Angle) and (i > Length (s)) then ...
  132.  
  133.   (The check `i > Length (s)' is in case you don't want to accept
  134.   trailing "garbage".)
  135. }
  136.  
  137. { Just skip any space characters as described above. }
  138. procedure StrSkipSpaces (const s : String; var i : Integer);
  139.  
  140. { Read a quoted string (as produced by QuoteString) from a string
  141.   and unquote the result using UnQuoteString. It is considered
  142.   failure if the result (unquoted) would be longer than the capacity
  143.   of Dest.}
  144. function  StrReadQuoted (const s : String; var i : Integer; var Dest : String) : Boolean;
  145.  
  146. { Read a string delimited with Delimiter from a string and return
  147.   the result with the delimiters removed. It is considered failure
  148.   if the result (without delimiters) would be longer than the
  149.   capacity of Dest. }
  150. function  StrReadDelimited (const s : String; var i : Integer; var Dest : String; Delimiter : Char) : Boolean;
  151.  
  152. { Read a word (consisting of anything but space characters and
  153.   commas) from a string. It is considered failure if the result
  154.   would be longer than the capacity of Dest. }
  155. function  StrReadWord (const s : String; var i : Integer; var Dest : String) : Boolean;
  156.  
  157. { Check that a certain string is contained in s (after possible
  158.   space characters). }
  159. function  StrReadConst (const s : String; var i : Integer; const Expected : String) : Boolean;
  160.  
  161. { A simpler to use version of StrReadConst that expects a `,'. }
  162. function  StrReadComma (const s : String; var i : Integer) : Boolean;
  163.  
  164. { Read an integer number from a string. }
  165. function  StrReadInt (const s : String; var i : Integer; var Dest : Integer) : Boolean;
  166.  
  167. { Read a real number from a string. }
  168. function  StrReadReal (const s : String; var i : Integer; var Dest : Real) : Boolean;
  169.  
  170. { Read a Boolean value, represented by a single character
  171.   from CharactersTrue or CharactersFalse (cf. Char2Boolean), from a
  172.   string. }
  173. function  StrReadBoolean (const s : String; var i : Integer; var Dest : Boolean) : Boolean;
  174.  
  175. { Read an enumerated value, i.e., one of the entries of IDs, from a
  176.   string, and stores the ordinal value, i.e., the index in IDs
  177.   (always zero-based) in Dest. }
  178. function  StrReadEnum (const s : String; var i : Integer; var Dest : Integer; var IDs : array of PString) : Boolean;
  179.  
  180. { String hash table }
  181.  
  182. const
  183.   DefaultHashSize = 1403;
  184.  
  185. type
  186.   THash = Cardinal;
  187.  
  188.   PStrHashList = ^TStrHashList;
  189.   TStrHashList = record
  190.     Next : PStrHashList;
  191.     s : PString;
  192.     i : Integer;
  193.     p : Pointer
  194.   end;
  195.  
  196.   PStrHashTable = ^TStrHashTable;
  197.   TStrHashTable (Size : Cardinal) = record
  198.     CaseSensitive : Boolean;
  199.     Table : array [0 .. Size - 1] of PStrHashList
  200.   end;
  201.  
  202. function  HashString          (const s : String) : THash;
  203. function  NewStrHashTable     (Size : Cardinal; CaseSensitive : Boolean) : PStrHashTable;
  204. procedure AddStrHashTable     (HashTable : PStrHashTable; s : String; i : Integer; p : Pointer);
  205. procedure DeleteStrHashTable  (HashTable : PStrHashTable; s : String);
  206. function  SearchStrHashTable  (HashTable : PStrHashTable; const s : String; var p : Pointer) : Integer; { p may be null }
  207. procedure DisposeStrHashTable (HashTable : PStrHashTable);
  208.  
  209. implementation
  210.  
  211. procedure AppendStr (var s : String; const Source : String);
  212. begin
  213.   Insert (Source, s, Length (s) + 1)
  214. end;
  215.  
  216. procedure StrCut (var s : String; MaxLength : Integer);
  217. begin
  218.   if Length (s) > MaxLength then Delete (s, MaxLength + 1, Length (s) - MaxLength)
  219. end;
  220.  
  221. function StrCount (const SubStr : String; s : String) : Integer;
  222. var c, p : Integer;
  223. begin
  224.   if SubStr = '' then
  225.     StrCount := 0
  226.   else
  227.     begin
  228.       c := 0;
  229.       p := 1;
  230.       repeat
  231.         p := PosFrom (SubStr, s, p);
  232.         if p <> 0 then
  233.           begin
  234.             Inc (c);
  235.             Inc (p, Length (SubStr))
  236.           end
  237.       until p = 0;
  238.       StrCount := c
  239.     end
  240. end;
  241.  
  242. function StrReplace (const s, Source, Dest : String) = Result : TString;
  243. var c : Integer;
  244. begin
  245.   Result := s;
  246.   for c := Length (Result) - Length (Source) + 1 downto 1 do
  247.     if Copy (Result, c, Length (Source)) = Source then
  248.       begin
  249.         Delete (Result, c, Length (Source));
  250.         Insert (Dest, Result, c)
  251.       end
  252. end;
  253.  
  254. function Char2Boolean (ch : Char; var Dest : Boolean) : Boolean;
  255. begin
  256.   Char2Boolean := True;
  257.   Dest := False;
  258.   if ch in CharactersTrue then
  259.     Dest := True
  260.   else if not (ch in CharactersFalse) then
  261.     Char2Boolean := False
  262. end;
  263.  
  264. function Char2Digit (ch : Char) : Integer;
  265. begin
  266.   case ch of
  267.     '0' .. '9': Char2Digit := Ord (ch) - Ord ('0');
  268.     'A' .. 'Z': Char2Digit := Ord (ch) - Ord ('A') + $a;
  269.     'a' .. 'z': Char2Digit := Ord (ch) - Ord ('a') + $a;
  270.     else        Char2Digit := -1
  271.   end
  272. end;
  273.  
  274. function QuoteString (const s : String) : TString;
  275. const HexChars : array [0 .. $f] of Char = '0123456789ABCDEF';
  276. var
  277.   q, t : TString;
  278.   i, n : Integer;
  279. begin
  280.   q := s;
  281.   i := 0;
  282.   repeat
  283.     i := CharPosFrom ([#0 .. Pred (' '), '"', '=', #127 .. High (Char)], q, i + 1);
  284.     if i = 0 then Break;
  285.     n := Ord (q [i]);
  286.     t := HexChars [n div $10] + HexChars [n mod $10];
  287.     Insert (t, q, i + 1);
  288.     q [i] := '=';
  289.     Inc (i, Length (t))
  290.   until False;
  291.   QuoteString := '"' + q + '"'
  292. end;
  293.  
  294. function UnQPString (var s : String) : Boolean;
  295. var i, j : Integer;
  296. begin
  297.   UnQPString := False;
  298.   repeat
  299.     i := Pos (' ' + NewLine, s);
  300.     if i = 0 then Break;
  301.     j := i;
  302.     while (j > 1) and (s [j - 1] = ' ') do Dec (j);
  303.     Delete (s, j, i - j + 1)
  304.   until False;
  305.   i := 0;
  306.   repeat
  307.     i := PosFrom ('=', s, i + 1);
  308.     if i = 0 then Break;
  309.     if (i <= Length (s) - 2) and (s [i + 1] in ['0' .. '9', 'A' .. 'F', 'a' .. 'f'])
  310.                              and (s [i + 2] in ['0' .. '9', 'A' .. 'F', 'a' .. 'f']) then
  311.       begin
  312.         s [i] := Chr ($10 * Char2Digit (s [i + 1]) + Char2Digit (s [i + 2]));
  313.         Delete (s, i + 1, 2)
  314.       end
  315.     else if (i <= Length (s) - 1) and (s [i + 1] = NewLine) then
  316.       begin
  317.         Delete (s, i, 2);
  318.         Dec (i)
  319.       end
  320.     else
  321.       Exit
  322.   until False;
  323.   UnQPString := True
  324. end;
  325.  
  326. function UnQuoteString (var s : String) : Boolean;
  327. begin
  328.   UnQuoteString := False;
  329.   if (Length (s) < 2) or (s [1] <> '"') or (s [Length (s)] <> '"') then Exit;
  330.   Delete (s, 1, 1);
  331.   Delete (s, Length (s), 1);
  332.   UnQuoteString := UnQPString (s)
  333. end;
  334.  
  335. function ExpandTabs (var s : String; TabSize : Integer) : Boolean;
  336. const chTab = #9;
  337. var i, TabSpaces : Integer;
  338. begin
  339.   ExpandTabs := True;
  340.   repeat
  341.     i := Pos (chTab, s);
  342.     if i = 0 then Break;
  343.     TabSpaces := TabSize - (i - 1) mod TabSize;
  344.     if Length (s) + TabSpaces - 1 > High (s) then
  345.       begin
  346.         ExpandTabs := False;
  347.         Break
  348.       end;
  349.     Delete (s, i, 1);
  350.     Insert (StringOfChar (' ', TabSpaces), s, i)
  351.   until False
  352. end;
  353.  
  354. function ExpandCEscapeSequences (const s : String; RemoveQuoteChars, AllowOctal : Boolean) = r : TString;
  355. const chEsc = #27;
  356. var
  357.   i, c, Digit, v : Integer;
  358.   DelFlag : Boolean;
  359. begin
  360.   r := s;
  361.   i := 1;
  362.   while i < Length (r) do
  363.     begin
  364.       if r [i] = '\' then
  365.         begin
  366.           DelFlag := True;
  367.           case r [i + 1] of
  368.             'n' : r [i + 1] := "\n";
  369.             't' : r [i + 1] := "\t";
  370.             'r' : r [i + 1] := "\r";
  371.             'f' : r [i + 1] := "\f";
  372.             'b' : r [i + 1] := "\b";
  373.             'v' : r [i + 1] := "\v";
  374.             'a' : r [i + 1] := "\a";
  375.             'e',
  376.             'E' : r [i + 1] := chEsc;
  377.             'x' : begin
  378.                     v := 0;
  379.                     c := 2;
  380.                     while i + c <= Length (r) do
  381.                       begin
  382.                         Digit := Char2Digit (r [i + c]);
  383.                         if (Digit < 0) or (Digit >= $10) then Break;
  384.                         v := $10 * v + Digit;
  385.                         Inc (c)
  386.                       end;
  387.                     Delete (r, i + 1, c - 2);
  388.                     r [i + 1] := Chr (v)
  389.                   end;
  390.             '0' .. '7' : if AllowOctal then
  391.                            begin
  392.                              v := 0;
  393.                              c := 1;
  394.                              repeat
  395.                                v := 8 * v + Ord (r [i + c]) - Ord ('0');
  396.                                Inc (c)
  397.                              until (i + c > Length (r)) or (c > 3) or not (r [i + c] in ['0' .. '7']);
  398.                              Delete (r, i + 1, c - 2);
  399.                              r [i + 1] := Chr (v)
  400.                            end
  401.                          else
  402.                            DelFlag := False;
  403.             else DelFlag := False
  404.           end;
  405.           if DelFlag or RemoveQuoteChars then
  406.             Delete (r, i, 1)
  407.           else
  408.             Inc (i)
  409.         end;
  410.       Inc (i)
  411.     end
  412. end;
  413.  
  414. procedure StrSkipSpaces (const s : String; var i : Integer);
  415. begin
  416.   while (i <= Length (s)) and (s [i] in SpaceCharacters) do Inc (i)
  417. end;
  418.  
  419. function StrReadQuoted (const s : String; var i : Integer; var Dest : String) : Boolean;
  420. var
  421.   j : Integer;
  422.   s1 : TString;
  423. begin
  424.   StrReadQuoted := False;
  425.   StrSkipSpaces (s, i);
  426.   if (i >= Length (s)) or (s [i] <> '"') then Exit;
  427.   j := PosFrom ('"', s, i + 1);
  428.   if j = 0 then Exit;
  429.   s1 := s [i .. j];
  430.   i := j + 1;
  431.   if not UnQuoteString (s1) or (Length (s1) > GetStringCapacity (Dest)) then Exit;
  432.   Dest := s1;
  433.   StrReadQuoted := True
  434. end;
  435.  
  436. function StrReadDelimited (const s : String; var i : Integer; var Dest : String; Delimiter : Char) : Boolean;
  437. var j : Integer;
  438. begin
  439.   StrReadDelimited := False;
  440.   StrSkipSpaces (s, i);
  441.   if (i >= Length (s)) or (s [i] <> Delimiter) then Exit;
  442.   j := PosFrom (Delimiter, s, i + 1);
  443.   if (j = 0) or (j - i - 1 > GetStringCapacity (Dest)) then Exit;
  444.   Dest := s [i + 1 .. j - 1];
  445.   i := j + 1;
  446.   StrReadDelimited := True
  447. end;
  448.  
  449. function StrReadWord (const s : String; var i : Integer; var Dest : String) : Boolean;
  450. var j : Integer;
  451. begin
  452.   StrReadWord := False;
  453.   StrSkipSpaces (s, i);
  454.   if i > Length (s) then Exit;
  455.   j := CharPosFrom (SpaceCharacters + [','], s, i + 1);
  456.   if j = 0 then j := Length (s) + 1;
  457.   if j - i > GetStringCapacity (Dest) then Exit;
  458.   Dest := s [i .. j - 1];
  459.   i := j;
  460.   StrReadWord := True
  461. end;
  462.  
  463. function StrReadConst (const s : String; var i : Integer; const Expected : String) = Res : Boolean;
  464. begin
  465.   StrSkipSpaces (s, i);
  466.   Res := Copy (s, i, Length (Expected)) = Expected;
  467.   if Res then Inc (i, Length (Expected))
  468. end;
  469.  
  470. function StrReadComma (const s : String; var i : Integer) = Res : Boolean;
  471. begin
  472.   StrSkipSpaces (s, i);
  473.   Res := (i <= Length (s)) and (s [i] = ',');
  474.   if Res then Inc (i)
  475. end;
  476.  
  477. function StrReadInt (const s : String; var i : Integer; var Dest : Integer) : Boolean;
  478. var j, e : Integer;
  479. begin
  480.   StrReadInt := False;
  481.   StrSkipSpaces (s, i);
  482.   if i > Length (s) then Exit;
  483.   j := i + 1;  { This is so Val gets at least one character. Also, a possible
  484.                  `-' sign is covered here, and does not have to be included
  485.                  in the set in the following statement. }
  486.   while (j <= Length (s)) and (s [j] in ['0' .. '9']) do Inc (j);
  487.   Val (s [i .. j - 1], Dest, e);
  488.   if e <> 0 then Exit;
  489.   i := j;
  490.   StrReadInt := True
  491. end;
  492.  
  493. function StrReadReal (const s : String; var i : Integer; var Dest : Real) : Boolean;
  494. var j, e : Integer;
  495. begin
  496.   StrReadReal := False;
  497.   StrSkipSpaces (s, i);
  498.   if i > Length (s) then Exit;
  499.   j := i + 1;  { This is so Val gets at least one character. Also, a possible
  500.                  `-' sign is covered here, and does not have to be included
  501.                  in the set in the following statement. }
  502.   while (j <= Length (s)) and (s [j] in ['0' .. '9', '+', '-', '.', 'E', 'e']) do Inc (j);
  503.   Val (s [i .. j - 1], Dest, e);
  504.   if e <> 0 then Exit;
  505.   i := j;
  506.   StrReadReal := True
  507. end;
  508.  
  509. function StrReadBoolean (const s : String; var i : Integer; var Dest : Boolean) : Boolean;
  510. begin
  511.   StrReadBoolean := False;
  512.   StrSkipSpaces (s, i);
  513.   if (i > Length (s)) or not Char2Boolean (s [i], Dest) then Exit;
  514.   Inc (i);
  515.   StrReadBoolean := True
  516. end;
  517.  
  518. function StrReadEnum (const s : String; var i : Integer; var Dest : Integer; var IDs : array of PString) : Boolean;
  519. var
  520.   c, j : Integer;
  521.   s1 : TString;
  522. begin
  523.   StrReadEnum := False;
  524.   StrSkipSpaces (s, i);
  525.   j := PosFrom (',', s, i);
  526.   if j = 0 then j := Length (s) + 1;
  527.   s1 := s [i .. j - 1];
  528.   c := 0;
  529.   while (c <= High (IDs)) (*@@fjf226 and*)do begin if not  (s1 <> IDs [c]^) then break(*do*); Inc (c); (**)end;
  530.   if c > High (IDs) then Exit;
  531.   Dest := c;
  532.   i := j;
  533.   StrReadEnum := True
  534. end;
  535.  
  536. function HashString (const s : String) : THash;
  537. var Hash, i : THash;
  538. begin
  539.   Hash := Length (s);
  540.   for i := 1 to Length (s) do
  541.     (*@@$localR-*) Hash := Hash shl 2 + Ord (s [i]); (*@@$endlocal*)
  542.   HashString := Hash
  543. end;
  544.  
  545. function NewStrHashTable (Size : Cardinal; CaseSensitive : Boolean) = HashTable : PStrHashTable;
  546. var i : Cardinal;
  547. begin
  548.   New (HashTable, Size);
  549.   HashTable^.CaseSensitive := CaseSensitive;
  550.   for i := 0 to HashTable^.Size - 1 do HashTable^.Table [i] := nil
  551. end;
  552.  
  553. procedure AddStrHashTable (HashTable : PStrHashTable; s : String; i : Integer; p : Pointer);
  554. var
  555.   Hash : THash;
  556.   pl : PStrHashList;
  557. begin
  558.   if not HashTable^.CaseSensitive then LoCaseString (s);
  559.   Hash := HashString (s) mod HashTable^.Size;
  560.   New (pl);
  561.   pl^.s := NewString (s);
  562.   pl^.i := i;
  563.   pl^.p := p;
  564.   pl^.Next := HashTable^.Table [Hash];
  565.   HashTable^.Table [Hash] := pl
  566. end;
  567.  
  568. procedure DeleteStrHashTable (HashTable : PStrHashTable; s : String);
  569. var
  570.   Hash : THash;
  571.   pl : PStrHashList;
  572.   ppl : ^PStrHashList;
  573. begin
  574.   if not HashTable^.CaseSensitive then LoCaseString (s);
  575.   Hash := HashString (s) mod HashTable^.Size;
  576.   ppl := @HashTable^.Table [Hash];
  577.   while (ppl^ <> nil) and (ppl^^.s^ <> s) do ppl := @ppl^^.Next;
  578.   if ppl^ <> nil then
  579.     begin
  580.       pl := ppl^;
  581.       ppl^ := pl^.Next;
  582.       Dispose (pl^.s);
  583.       Dispose (pl)
  584.     end
  585. end;
  586.  
  587. function SearchStrHashTable (HashTable : PStrHashTable; const s : String; var p : Pointer) : Integer;
  588. var
  589.   Hash : THash;
  590.   pl : PStrHashList;
  591.   ps : ^const String;
  592.   sl : String (Length (s));
  593. begin
  594.   if HashTable^.CaseSensitive then
  595.     ps := @s
  596.   else
  597.     begin
  598.       sl := LoCaseStr (s);
  599.       ps := @sl
  600.     end;
  601.   Hash := HashString (ps^) mod HashTable^.Size;
  602.   pl := HashTable^.Table [Hash];
  603.   while (pl <> nil) and (pl^.s^ <> ps^) do pl := pl^.Next;
  604.   if pl = nil then
  605.     begin
  606.       if @p <> nil then p := nil;
  607.       SearchStrHashTable := 0
  608.     end
  609.   else
  610.     begin
  611.       if @p <> nil then p := pl^.p;
  612.       SearchStrHashTable := pl^.i
  613.     end
  614. end;
  615.  
  616. procedure DisposeStrHashTable (HashTable : PStrHashTable);
  617. var
  618.   i : Cardinal;
  619.   pl, pt : PStrHashList;
  620. begin
  621.   for i := 0 to HashTable^.Size - 1 do
  622.     begin
  623.       pl := HashTable^.Table [i];
  624.       HashTable^.Table [i] := nil;
  625.       while pl <> nil do
  626.         begin
  627.           pt := pl;
  628.           pl := pl^.Next;
  629.           Dispose (pt^.s);
  630.           Dispose (pt)
  631.         end
  632.     end
  633. end;
  634.  
  635. end.
  636.